package com.module.netty;

import com.module.netty.handle.client.MessageClientHandler;
import com.module.netty.handle.server.MessageServerHandler;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * netty Reactor
 * @author chenluqiang
 * @date 2019年3月22日 下午3:14:40 
 *
 */
public class NettyUtils {
	
	private static Integer port = 2333;
	private static String host = "127.0.0.1";
	
	public static void nettyServer() {
		// 相当于主 Reactor
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		// 相当于从 Reactor(多路复用，高性能设计模式， )
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			// bootstrap协议
			ServerBootstrap serverBootstrap = new ServerBootstrap();
			serverBootstrap.group(bossGroup, workerGroup);
			serverBootstrap.channel(NioServerSocketChannel.class);
			
			serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

				@Override
				protected void initChannel(SocketChannel  ch) throws Exception {
					ch.pipeline().addLast(new MessageServerHandler());
				}
			});
			//worker 客户端socket链接设置，一个客户端链接就有一个
			serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);
			//服务器 socket 链接设置，一个服务器只有一个
			serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
			ChannelFuture f = serverBootstrap.bind(port).sync();
			f.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			workerGroup.shutdownGracefully();
			bossGroup.shutdownGracefully();
		}
	}
	
	public static void nettyClient() {
		//
		EventLoopGroup workGrop = new NioEventLoopGroup();
		try {
			Bootstrap b = new Bootstrap();
			b.group(workGrop);
			b.channel(NioSocketChannel.class);
			b.option(ChannelOption.SO_KEEPALIVE, true);
			b.handler(new ChannelInitializer<SocketChannel>() {

				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					ch.pipeline().addLast(new MessageClientHandler());
				}
			});

			ChannelFuture f = b.connect(host, port).sync();
			f.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			workGrop.shutdownGracefully();
		}
	}
	

	private static String convertByteBufToString(ByteBuf buf) {
	    String str;
	    if(buf.hasArray()) { // 处理堆缓冲区
	        str = new String(buf.array(), buf.arrayOffset() + buf.readerIndex(), buf.readableBytes());
	    } else { // 处理直接缓冲区以及复合缓冲区
	        byte[] bytes = new byte[buf.readableBytes()];
	        buf.getBytes(buf.readerIndex(), bytes);
	        str = new String(bytes, 0, buf.readableBytes());
	    }
	    return str;
	}

	public static void send(ChannelHandlerContext ctx, String message) {
		final ByteBuf msg = ctx.alloc().buffer();
		msg.writeBytes(message.getBytes());
		ctx.writeAndFlush(msg);		
	}
	
	public static String say(Object message) {
		return convertByteBufToString((ByteBuf)message);
	}
	
	public static void main(String[] args) {
		nettyServer();
	}

}
